package com.jay.conf;

import com.alipay.jarslink.api.ModuleConfig;
import com.alipay.jarslink.api.ModuleLoader;
import com.alipay.jarslink.api.ModuleManager;
import com.alipay.jarslink.api.impl.AbstractModuleRefreshScheduler;
import com.alipay.jarslink.api.impl.ModuleClassLoader;
import com.alipay.jarslink.api.impl.ModuleLoaderImpl;
import com.alipay.jarslink.api.impl.ModuleManagerImpl;
import com.alipay.jarslink.utils.ModuleUtils;
import com.google.common.collect.ImmutableList;
import com.jay.utils.FileURL;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;


@Configuration
@ConfigurationProperties(prefix = "custom.jarslink")
public class JarSlinkConfiguration {
	
	private String pluginPath;
	
	private int refreshDelay;

	public int getRefreshDelay() {
		return refreshDelay;
	}

	public void setRefreshDelay(int refreshDelay) {
		this.refreshDelay = refreshDelay;
	}

	public String getPluginPath() {
		return pluginPath;
	}

	public void setPluginPath(String pluginPath) {
		this.pluginPath = pluginPath;
	}

	@Bean
	public ModuleLoader moduleLoader() {
		return new ModuleLoaderImpl();
	}
	
	@Bean
	public ModuleManager moduleManager() {
		return new ModuleManagerImpl();
	}
	
	@Bean
	public AbstractModuleRefreshScheduler moduleRefreshScheduler(ModuleLoader moduleLoader, ModuleManager moduleManager) {
		AbstractModuleRefreshScheduler moduleRefreshScheduler = new ModuleRefreshSchedulerImpl();
		moduleRefreshScheduler.setModuleLoader(moduleLoader);
		moduleRefreshScheduler.setModuleManager(moduleManager);
		((ModuleRefreshSchedulerImpl)moduleRefreshScheduler).setPluginPath(pluginPath);
		moduleRefreshScheduler.setRefreshDelay(refreshDelay);
		return moduleRefreshScheduler;
	}
	
	public static class ModuleRefreshSchedulerImpl extends AbstractModuleRefreshScheduler {
		
		private static final Logger LOGGER = LoggerFactory
	            .getLogger(ModuleRefreshSchedulerImpl.class);
		
		// 类加载器加载的包
		private static final String OVERRIDE_PACKAGES = "com.jay";
		
		private String pluginPath;
		
		public String getPluginPath() {
			return pluginPath;
		}

		public void setPluginPath(String pluginPath) {
			this.pluginPath = pluginPath;
		}

		@Override
		public List<ModuleConfig> queryModuleConfigs() {
			// 加载插件文件夹下所有的jar文件
			if (StringUtils.isEmpty(pluginPath)) {
				throw new RuntimeException("jar plugins dir path is empty!!!");
			}
			File file = new File(pluginPath);
			if (!file.exists() || !file.isDirectory()) {
				throw new RuntimeException("jar plugins dir is not exist!!!");
			}
			LOGGER.info("load plugin from :" + pluginPath);
			List<File> jarFileList = filterJars(file.listFiles());
			List<ModuleConfig> moduleConfigs = new ArrayList<>(16);
			if (jarFileList.size() > 0) {
				for (File jarFile : jarFileList) {
					ClassLoader current = Thread.currentThread().getContextClassLoader();
					try {
						URL moduleJar = null;
						Properties configProperties = null;
						// 模块路径
						moduleJar = getURL(jarFile);
						ModuleClassLoader classLoder = new ModuleClassLoader(ImmutableList.of(moduleJar), current, null);
						Thread.currentThread().setContextClassLoader(classLoder);
						// 获取jar包里面模块名称
						ModuleConfig config = new ModuleConfig();
						config.setEnabled(true);
//						config.setModuleUrl(ImmutableList.copyOf(ModuleUtils.getJarLib(moduleJar)));
						config.setModuleUrl(ImmutableList.of(moduleJar));
						// 获得模块配置信息
						configProperties = ModuleUtils.getModuleConfig(moduleJar);
						config.setName(ModuleUtils.getConfigValue(configProperties, ModuleUtils.MODULE_PROPERTY_NAME, jarFile.getName()));
						config.setOverridePackages(ImmutableList.copyOf(ModuleUtils.getConfigValue(configProperties, ModuleUtils.MODULE_OVERPACKAGE, OVERRIDE_PACKAGES).split(",")));
						config.setVersion("jar_plugin_" + ModuleUtils.getConfigValue(configProperties, ModuleUtils.MODULE_PROPERTY_NAME, jarFile.getName() )+ "_" +jarFile.lastModified());
						moduleConfigs.add(config);
						ModuleUtils.releaseProperties(configProperties);
					} catch (Exception e) {
						throw new RuntimeException(e);
					} finally {
						Thread.currentThread().setContextClassLoader(current);
					}
				}
			}
			return ImmutableList.copyOf(moduleConfigs);
		}

		private URL getURL(File jarFile) throws MalformedURLException {
			URL moduleJar;
			String userdir = System.getProperty("user.dir");
			System.setProperty("user.dir", "");
			moduleJar = FileURL.makeURL(jarFile.getAbsolutePath());
			System.setProperty("user.dir", userdir);
			return moduleJar;
		}
		
		private List<File> filterJars(File[] files){
			List<File> result = new ArrayList<>(16);
			if (null != files && files.length > 0) {
				for (File file : files) {
					if (file.getName().endsWith(".jar")) {
						result.add(file);
					}
				}
			}
			return result;
		}

	}
}
